/*
 * @Author: xiangru.xiao xiangru.xiao@mthreads.com
 * @Date: 2023-05-10 16:38:07
 * @LastEditors: xiangru.xiao xiangru.xiao@mthreads.com
 * @LastEditTime: 2023-05-17 14:12:04
 * Copyright (c) 2023 by Moore Threads, All Rights Reserved. 
 */
#include <string>
#include <vector>
#include "objectfactory.h"
#include "node.h"
#include "cu_helper.h"

#define TEST_ITERS 50

class Bs_download_speed : public Node
{
public:
    Bs_download_speed()
    {
        nodeUint = "GBPS";
    }
    std::string name() override
    {
        return "bs-download-speed";
    }
    std::string describe() override
    {
        return "总线下载速度";
    }
    Node::NodeType  nodeType() override
    {
        return NodeTP_BsSpeed;
    }
protected:
    bool startup() override;
    bool perform() override;
    void shutdown() override;
private:
    std::vector<size_t> sizeList() const;
private:
    int        deviceid;
};

bool Bs_download_speed::startup()
{
    deviceid = deviceinfo->deviceID();
    CHECK_CUDA_ERROR(cudaSetDevice(deviceid));
    return true;
}

bool Bs_download_speed::perform()
{
    float fTime = 0;
    std::vector<size_t> ls = sizeList();
    for (int i = 0; i < ls.size(); ++i) {
        const size_t dataSize = ls[i] * 1024;
        void *h_in, *d_in;
        CHECK_CUDA_ERROR(cudaMallocHost(&h_in, dataSize));
        CHECK_CUDA_ERROR(cudaMalloc(&d_in, dataSize));
        float ltime  = 0;
        for (int j = 0; j < TEST_ITERS; ++j) {
            float duration = 0;
            {
                CUDAEvent evt(&duration);
                CHECK_CUDA_ERROR(cudaMemcpy(d_in, h_in, dataSize, cudaMemcpyHostToDevice));
                CHECK_CUDA_ERROR(cudaDeviceSynchronize());
            }
            ltime += duration;
        }
        CHECK_CUDA_ERROR(cudaFreeHost(h_in));
        CHECK_CUDA_ERROR(cudaFree(d_in));
        fTime +=  float(dataSize) * TEST_ITERS / ltime / 1e6f;
    }
    nodeValue = fTime / ls.size();
    return true;
}

void Bs_download_speed::shutdown()
{

}

std::vector<size_t> Bs_download_speed::sizeList() const
{
    std::vector<size_t> list;
    size_t sizes[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384,
                      32768, 65536, 131072, 262144
                     };
    const size_t nSizes =  sizeof(sizes) / sizeof (sizes[0]);
    for (int i = 0; i < nSizes; ++i) 
    {
        list.push_back(sizes[i]);
    }
    return list;
}
REGISTER_OBJECT(Node, Bs_download_speed)
